package com.dongzili.query.common.base;

import cn.hutool.core.util.ReflectUtil;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;


import com.dongzili.query.common.config.mybatisplus.MybatisPlusUtil;
import com.dongzili.query.common.utils.LocalDateUtils;
import com.dongzili.query.common.utils.ReflectUtils;
import com.dongzili.query.common.vo.*;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @param <T>
 */
public class BaseController<T> {

    private final Class<T> tClass;

    public BaseController(){
        Type superClass = getClass().getGenericSuperclass();
        if (superClass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) superClass;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            this.tClass = (Class<T>) actualTypeArguments[0];
        } else {
            throw new IllegalArgumentException(superClass.getTypeName()+"类使用泛型类型参数化失败...");
        }
    }
    /**
     * 新增
     * @param request 数据实体变动请求参数
     * @return R<T>
     */
    @PostMapping("/insert")
    public R<T> insert(@RequestBody InsertDataRequest<T> request) {
        return R.success(new BaseServiceUtils<>(tClass).insert(request));
    }

    /**
     * 根据id更新
     * @param data
     * @return
     */
    @PostMapping("/updateById")
    public R<T> updateById(@RequestBody T data) {
        T entity = new BaseServiceUtils<>(tClass).updateById(data);
        return R.success(entity);
    }

    /**
     * 根据id删除
     * @param id
     * @return
     */
    @GetMapping("/deleteById{id}")
    public R<Boolean> deleteById(@PathVariable(value = "id") Long id) {
        boolean result = new BaseServiceUtils<>(tClass).deleteById(id);
        return R.success(result);
    }

    /**
     * 根据id查询
     * @param id
     * @return
     */
    @GetMapping("/selectById/{id}")
    public R<T> selectById(@PathVariable(value = "id") Long id) {
        T entity = new BaseServiceUtils<>(tClass).selectById(id);
        return R.success(entity);
    }


    public QueryWrapper<T> customWrapper(PageRequest<T> request){
        return null;
    }

    /**
     * 分页查询
     */
    @PostMapping(value = "/page")
    public R<Page<T>>  page(@RequestBody PageRequest<T> request) {
        QueryWrapper<T> queryWrapper = customWrapper(request);
        if(queryWrapper == null){
            queryWrapper = new QueryWrapper<>(request.getEntity());
            T entity = request.getEntity();
            if(!request.isQueryDeleted()){
                if(ReflectUtil.hasField(tClass, "deleted")){
                    Object deleted = ReflectUtil.getFieldValue(entity, "deleted");
                    if(deleted == null){
                        queryWrapper.eq("deleted", 0);
                    }
                }
            }
            if(request.getQueryPeriod() != null){
                Map<String, QueryPeriodVo> queryPeriodMap = request.getQueryPeriod();
                for (Map.Entry<String, QueryPeriodVo> queryPeriod : queryPeriodMap.entrySet()){
                    String key = queryPeriod.getKey();
                    if (!StringUtils.hasText(key)){
                        continue;
                    }
                    QueryPeriodVo queryPeriodVo = queryPeriod.getValue();
                    if(queryPeriodVo != null && queryPeriodVo.getStartTime() != null && queryPeriodVo.getEndTime() != null){
                        queryWrapper.between(key, queryPeriodVo.getStartTime(), queryPeriodVo.getEndTime());
                    }else if(queryPeriodVo != null){
                        if(queryPeriodVo.getStartTime() != null){
                            queryWrapper.ge(key, LocalDateUtils.getStartTimeOfDay(queryPeriodVo.getStartTime().toLocalDate()));
                        }else if(queryPeriodVo.getEndTime() != null){
                            queryWrapper.le(key, LocalDateUtils.getLastTimeOfDay(queryPeriodVo.getEndTime().toLocalDate()));
                        }
                    }
                }
            }
            // like 字段用 or 连接
            Map<String, Object> fieldValueMap = ReflectUtils.getNotNullFieldValueMap(request.getLikeEntity());
            if(!fieldValueMap.isEmpty()){
                queryWrapper.and(child -> {
                    for (Map.Entry<String, Object> entry : fieldValueMap.entrySet()){
                        child.or().like(entry.getKey(), entry.getValue());
                    }
                });
            }

            if(request.getOrders()!=null && !request.getOrders().isEmpty()){
                for (OrderVo orderVo : request.getOrders()){
                    if(OrderType.Desc.equals(orderVo.getOrderType())){
                        queryWrapper.orderByDesc(orderVo.getFieldName());
                    }else{
                        queryWrapper.orderByAsc(orderVo.getFieldName());
                    }
                }
            }
            if(ReflectUtil.hasField(tClass, "createTime") && request.getYear() != null){
                queryWrapper.eq("year(createTime)", request.getYear());
            }
            if(ReflectUtil.hasField(tClass, "createTime") && request.getMonth() != null){
                queryWrapper.eq("DATE_FORMAT(createTime, '%Y-%m')", request.getMonth());
            }
        }
        Page<T> page = MybatisPlusUtil.getMapper(tClass).selectPage(new Page<>(request.getCurrent(),request.getSize()), queryWrapper);

        return R.success(page);
    }

    /**
     * 批量删除
     */
    @PostMapping("/deleteByIds")
    @Transactional(rollbackFor = Exception.class)
    public R<?> deleteByIds(@RequestBody List<Long> ids){
        return R.success(MybatisPlusUtil.getMapper(tClass).deleteBatchIds(ids));
    }

    @PostMapping("/getYear")
    public R<List<String>> getYear(@RequestBody DateTimeFieldInfo info){
        if(!StringUtils.hasText(info.getFieldName())){
            return R.error(ResponseCode.PARAM_ERROR);
        }
        String fieldName = info.getFieldName();
        if(!ReflectUtil.hasField(tClass, fieldName)){
            return R.error("字段不存在");
        }
        String columName = ReflectUtils.getFieldName(ReflectUtil.getField(tClass, fieldName));
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
//        queryWrapper.select("year("+columName+") as `key`, count(1) as `value`");
        queryWrapper.select("year("+columName+") as `key`");
        queryWrapper.groupBy("year("+columName+")");
        queryWrapper.orderByDesc("`key`");
        List<Map<String, Object>> map = MybatisPlusUtil.getMapper(tClass).selectMaps(queryWrapper);
        List<String> list = map.stream().map(m -> m.get("key").toString()).collect(Collectors.toList());
        return R.success(list);
    }

    @PostMapping("/getMonth")
    public R<List<String>> getMonth(@RequestBody DateTimeFieldInfo info, @RequestParam(value = "year", required = false) Integer year){
        if(!StringUtils.hasText(info.getFieldName())){
            return R.error(ResponseCode.PARAM_ERROR);
        }
        String fieldName = info.getFieldName();
        if(!ReflectUtil.hasField(tClass, fieldName)){
            return R.error("字段不存在");
        }
        String columName = ReflectUtils.getFieldName(ReflectUtil.getField(tClass, fieldName));
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        if(year != null){
            queryWrapper.eq("year("+columName+")", year);
        }
        queryWrapper.select("DATE_FORMAT("+columName+", '%Y-%m') as `key`");

        queryWrapper.groupBy("DATE_FORMAT("+columName+", '%Y-%m')");
        queryWrapper.orderByDesc("`key`");
        List<Map<String, Object>> map = MybatisPlusUtil.getMapper(tClass).selectMaps(queryWrapper);
        List<String> list = map.stream().map(m -> m.get("key").toString()).collect(Collectors.toList());
        return R.success(list);
    }


}
